/**
author:diqye
https://git.oschina.net/diqye/ipt.js
*/
!function(exports){

/*=======================*/
/*
	util js工具函数
*/
var util = (function (exports) {

    //遍历 并列执行 结果反馈给回调
    function map(arr, fn, call) {
            if (!arr || arr.length == 0) call();
            if (Object.prototype.toString.call(arr) === '[object Array]') {
                var rs = [],
                    rerr = null,
                    num = 1;
                for (var i = 0, l = arr.length; i < l; i++) {
                    ! function (t, i) {
                        fn(function (err, res) {
                            if (err) rerr = err;
                            else rs[i] = res;
                            if (num++ == l) call(rerr, rs);
                        }, t, i);
                    }(arr[i], i)
                }
            } else if (Object.prototype.toString.call(arr) === '[object Object]') {
                var keys = [],
                    num = 1,
                    rs = {},
                    rerr = null;
                for (var key in arr) keys.push(key);
                for (var key in arr) {
                    ! function (t, key) {
                        fn(function (err, res) {
                            if (err) rerr = err;
                            else rs[key] = res;
                            if (num++ == keys.length) call(rerr, rs);
                        }, t, key);
                    }(arr[key], key)
                }
            }
        }
        //遍历 序列执行 结果分级向下反馈
    function mapsear(arr, fn, call) {
            if (!arr || arr.length == 0) call();
            if (Object.prototype.toString.call(arr) === '[object Array]') {
                var rs = [],
                    rerr = null,
                    len = arr.length;
                ! function run(i) {
                    if (i == len) {
                        call(null, rs);
                        return;
                    }
                    var a = arr[i];
                    fn(function (err, para) {
                        if (err) {
                            call(err);
                            return;
                        }
                        rs[i] = para;
                        run(i + 1);
                    }, a, i);
                }(0);

            } else if (Object.prototype.toString.call(arr) === '[object Object]') {
                var keys = [],
                    rs = {};
                for (var key in arr) keys.push(key);
                var len = keys.length;
                ! function run(i) {
                    if (i == len) {
                        call(null, rs);
                        return;
                    }
                    var a = arr[keys[i]];
                    fn(function (err, para) {
                        if (err) {
                            call(err);
                            return;
                        }
                        rs[keys[i]] = para;
                        run(i + 1);
                    }, a, keys[i]);
                }(0);
            }
        }
        //数据类型判断
    var type = (function () {

        var r = {},
            types = ['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Null', 'Array','Object'];
        for (var i = 0, t; t = types[i++];) {
            ! function (t) {
                r['is' + t] = function (obj) {
                    return Object.prototype.toString.call(obj) === '[object ' + t + ']';
                }
            }(t)
        }
        return r;
    })();

    function each(arr, fn) {
        if (!arr || !arr.length) return;
        for (var i = 0, l = arr.length, t; i < l; i++) {
            t = arr[i];
            if (fn(t, i) === false) break;
        }
    }

    function toabspath(src) {
            var a = document.createElement('a');
            a.setAttribute('href', src);
            return a.href; //使用a.getAttribute('href')会不灵的
        }
        //修复document.head
    var dochead = document.head = document.head || document.getElementsByTagName('head')[0];

    function getCurrentScript() {
        if (document.currentScript) return document.currentScript;
        var r = null;
        each(dochead.getElementsByTagName('script'), function (t, i) {
            if (t.readyState === 'interactive') {
                r = t;
            }
        })
        if (r) return r;
        try {
            "呵呵".恶心的浏览器只能以恶心的方式去处理();
        } catch (e) {
            var stack = e.stack;
            if (!stack) {
                stack = (String(e).match(/if linked scipt \s+/g) || []).join(' ');
            }
            stack = stack.split(/[@ ]/g).pop();
            stack = stack[0] === '(' ? stack.slice(1, -1) : stack.replace(/\s/, '');
            return {
                src: stack.replace(/(:\d+)?:\d+$/i, "")
            };
        }
    }
	
	function isEmpty(obj){
		for(var key in obj)return false;
		return true;
	}
    return {
        dochead: dochead,
        each: each,
        map: map,
        mapsear: mapsear,
        type: type,
		isEmpty:isEmpty,
        getCurrentScript: getCurrentScript,
        toabspath: toabspath
    }
}());
/*=======================*/
/*
 动态引入资源 实现代码
 函数执行顺序:
 ipt->start->loadSrc->loadCss
 					  loadScript
*/
! function (exports, map, mapsear, each) {
	var p = {
		pres: [],
		timeid: null,
		status: 'done',
		loadsrc: {
			/*
			src:{
				status:string in loading|done|merge|pre|loaddes
				in				   加载中|执行完成|合并|预执行|加载依赖项中
				in 	status顺序 loading->pre|merge->loaddes->done
				exports:object
				fns:array in function in err,exports
				scriptend:function in err,exports
				des:array in string 依赖项
			}
			*/
		},
		amd:{}
	};

	function createLoadsrc(src, status) {
		status = status || 'loading'
		p.loadsrc[src] = {
			status: status,
			fns: [],
			scriptend: function () {}
		}
	}

	function loadsrcsFor(src) {
		return p.loadsrc[src];
	}

	function donesrcs(err, exprots, src, fn) {
		p.loadsrc[src].status = 'done';
		p.loadsrc[src].exports = exprots;
		each(p.loadsrc[src].fns, function (t) {
			t(err, exprots)
		});
		fn(err, exprots)
	}

	function loadSrc(src, fn) {
		src = util.toabspath(src);
		var load = loadsrcsFor(src);
		if (load && load.status === 'done') {
			fn(null, load.exports);
			return;
		} else if ((load && load.status === 'loading') || (load && load.status === 'merge')||(load && load.status === 'pre')) {
			load.fns.push(fn);
			return;
		}
		createLoadsrc(src);
		if (~src.split('?')[0].indexOf('.css')) {
			loadCss(src, function (err, node) {
				donesrcs(err, node, src, fn)
			});
		} else if (~src.split('?')[0].indexOf('.js')) {
			p.loadsrc[src].scriptend = fn;
			loadScript(src, function (err, n) {
				if (p.loadsrc[src].status == "loading" || p.loadsrc[src].status == "merge") {
					donesrcs(err, null, src, fn)
				}
			});
		}
	}

	function loadCss(src, fn) {
		var node = document.createElement('link');
		node.rel = 'stylesheet';
		node.href = src;
		util.dochead.insertBefore(node, util.dochead.firstChild);
		if (node.attachEvent) {
			node.attachEvent('onload', function () {
				fn(null, node)
			});
		} else {
			setTimeout(function () {
				poll(node, fn);
			}, 0); // for cache
		}

		function poll(node, callback) {
			var isLoaded = false;
			if (/webkit/i.test(navigator.userAgent)) { //webkit
				if (node['sheet']) {
					isLoaded = true;
				}
			} else if (node['sheet']) { // for Firefox
				try {
					if (node['sheet'].cssRules) {
						isLoaded = true;
					}
				} catch (ex) {
					// NS_ERROR_DOM_SECURITY_ERR
					if (ex.code === 1000) {
						isLoaded = true;
					}
				}
			}
			if (isLoaded) {
				setTimeout(function () {
					callback(null, node);
				}, 1);
			} else {
				setTimeout(function () {
					poll(node, callback);
				}, 10);
			}
		}
	}

	function loadScript(src, fn) {
		var node = document.createElement("script");
		node.setAttribute('async', 'async');
		var timeID
		var supportLoad = "onload" in node
		var onEvent = supportLoad ? "onload" : "onreadystatechange"
		node[onEvent] = function onLoad() {
			if (!supportLoad && !timeID && /complete|loaded/.test(node.readyState)) {
				timeID = setTimeout(onLoad)
				return
			}
			if (supportLoad || timeID) {
				clearTimeout(timeID)
				fn(null, node);
			}
		}
		util.dochead.insertBefore(node, util.dochead.firstChild);
		node.src = src;
		node.onerror = function (e) {
			fn(e);
		}
	}

	function iife(id, des, fn,amd) {
		if (util.type.isFunction(id)) {
			fn = id;
			id = null;
			des = null;
		}
		if (util.type.isArray(id)) {
			fn = des;
			des = id;
			id = null;
		}
		if (util.type.isFunction(des)) {
			fn = des;
			des = null;
		}
		if(p.amd[id])id=p.amd[id]
		var current = util.getCurrentScript() 
        current=current&& current.src;
		if (id) id = util.toabspath(id);
		id = id || current || util.toabspath('/');
		if (!p.loadsrc[id]) createLoadsrc(id, 'pre');
		else p.loadsrc[id].status = 'pre';
		if (id != current) {
			p.loadsrc[id].status = 'merge';
		}
		setTimeout(function () {
			p.loadsrc[id].status = 'loaddes';
			util.map(des, function (next, t, i) {
				if(p.amd[t])t=p.amd[t]
				var path = util.toabspath(t);
				if (p.loadsrc[path] && p.loadsrc[path].status === 'loaddes') { //循环依赖
					next();
					return;
				}
				loadSrc(path, next);
			}, function (err, rs) {
				var modudel = {
					exports: {}
				};
				if(amd){
					modudel.exports=fn.apply(modudel.exports,rs);
				}else{
					fn.apply(modudel.exports, [modudel.exports, modudel].concat(rs));
				}
				donesrcs(err,modudel.exports,id,p.loadsrc[id].scriptend);
			});
		})
	}

	function ipt(src, fn) {
		if(util.type.isObject(src)){
			for(key in src){
				p.amd[key]=src[key];
			}
			return arguments.callee;
		}
		if(p.amd[src])src=p.amd[src]
		p.pres.push({
			src: src,
			fn: fn
		});
		start();
		return arguments.callee;
	}
	ipt.wait = function (fn) {
		p.pres.push({
			fn: fn,
			wait: true
		});
		start();
		return this;
	}
	ipt.ipt = ipt;

	function start() {
		if (p.pres.length == 0 || p.status == 'runing') return;
		clearTimeout(p.timeid);
		p.timeid = setTimeout(function () {
			p.status = "runing";
			var a2rr = [],
				i = 0,
				waitfn = [function () {}];
			each(p.pres, function (t, i1) {
				if (t.wait) {
					waitfn[i] = t.fn;
					i++;
					return;
				}
				a2rr[i] = a2rr[i] || [];
				a2rr[i].push(t);
			});
			p.pres = [];
			mapsear(a2rr, function (end, t, i) {
				map(t, function (end1, t1, i1) {
					loadSrc(t1.src, function (err, node) {
						if (t1.fn) t1.fn(err, node);
						end1(err, node);
					});
				}, function (err, rs) {
					if (waitfn[i]) waitfn[i].apply(null, [err].concat(rs));
					end(err, rs);
				});
			}, function (err, rs) {
				if (err) {
					console.log('diqye-err', err);
					return;
				}
				p.status = 'done';
				start();
			});

		});
	}
	exports.ipt = ipt;
	exports.iife = iife;
	exports.define=function(id,des,fn){
		iife(id,des,fn,true);//amd规范
	};
	exports.define.amd=p.amd;
}(exports, util.map, util.mapsear, util.each);

/*=======================*/
}(this)